﻿using CommonLib.Attr;
using CommonLib.Base;
using CommonLib.CodeEntity;
using CommonLib.Util;
using System.Text.RegularExpressions;

namespace Oracle.Lexer;

[Order(4)]
public class ConditionLexer : BaseLexer
{
    public override bool Check()
    {
        var txt = Real;
        if (txt.StartsWith("NOT ")) return true;
        if (txt.StartsWith("AND ") || txt.StartsWith("AND(")) return false;
        if (txt.StartsWith("-")) txt = txt[1..];
        var marks = OracleConst.Marks.Where(m => txt.Contains(m));
        foreach (var mk in marks)
        {
            var pre = txt[..txt.IndexOf(mk)];
            if (pre.IsFull()) return true;
        }
        return false;
    }

    protected override BaseCodeEntity Run()
    {
        var entity = new ConditionCodeEntity();
        var list = new List<string>();
        var txt = Txt;
        if(txt.StartsWith("NOT "))
        {
            entity.NotFlag = true;
            txt= txt[3..].Trim();
        }
        GetSub(txt, list, entity);
        list.ForEach(s => entity.Cons.Add(SqlFactory.Create(s).Execute()));
        return entity;
    }

    private void GetSub(string str, List<string> list, ConditionCodeEntity entity)
    {
        var mark = GetMark(str);
        if (mark == null)
        {
            list.Add(str);
            return;
        }
        var sub = new List<string>();
        while (mark != null)
        {
            var left = str[..str.IndexOf(mark)].Trim();
            var rigth = str[(str.IndexOf(mark) + mark.Length)..].Trim();
            if (left.IsFull() && rigth.IsFull())
            {
                list.Add(ReplaceMark(left, sub));
                entity.Marks.Add(mark.Trim());
                mark = GetMark(rigth);
                if (mark == null)
                {
                    list.Add(rigth);
                    str = "";
                    break;
                }
                else str = rigth;
            }
            else
            {
                str = str.ReplaceFirst(mark, "÷");
                sub.Add(mark);
                mark = GetMark(str);
            }
        }
        str = ReplaceMark(str, sub);
        if (list.Count == 0)
        {
            var substr = str[1..^1];
            if (substr.IsFull())
            {
                GetSub(substr, list, entity);
                str = "";
            }
        }
        if (!string.IsNullOrEmpty(str)) list.Add(str);
    }

    private string ReplaceMark(string str, List<string> sub)
    {
        while (str.Contains('÷'))
        {
            str = str.ReplaceFirst("÷", sub[0]);
            sub.RemoveAt(0);
        }
        return str;
    }


    private string? GetMark(string str)
    {
        if (Regex.IsMatch(str, "^-\\d+$")) return null;
        if (str.StartsWith("-"))
        {
            str = str[1..];
        }
        var mark = OracleConst.Marks.FirstOrDefault(str.Contains);
        if (mark == null) return null;
        else
        {
            var left = str[..str.IndexOf(mark)];
            var nw = GetMark(left);
            if (nw == null) return mark;
            else return nw;
        }
    }
}

